interface EventType {
  readonly callback: TAnyFunction;
  readonly once: boolean;
}

type EventMap = Record<string, EventType[]>;

class EventEmitter {
  private static instance: EventEmitter;
  private eventMap: EventMap = {};

  public static getInstance() {
    if (!EventEmitter.instance) {
      EventEmitter.instance = new EventEmitter();
    }
    return EventEmitter.instance;
  }

  // 监听事件
  on(event: string, callback: TAnyFunction, once?: boolean) {
    if (!this.eventMap[event]) {
      this.eventMap[event] = [];
    }
    this.eventMap[event].push({
      callback,
      once: !!once,
    });
    return this;
  }

  // 监听事件一次
  once(event: string, callback: TAnyFunction) {
    return this.on(event, callback, true);
  }

  // 触发事件
  emit(event: string, ...args: any[]) {
    const events = this.eventMap[event] || [];
    let { length } = events;
    for (let i = 0; i < length; i += 1) {
      if (!events[i]) {
        // eslint-disable-next-line no-continue
        continue;
      }
      const { callback, once } = events[i];

      if (once) {
        events.splice(i, 1);
        if (events.length === 0) {
          delete this.eventMap[event];
        }
        length -= 1;
        i -= 1;
      }
      callback.apply(this, args);
    }
  }

  // 取消事件监听
  off(event?: string, callback?: TAnyFunction) {
    if (!event) {
      // event 为空全部清除
      this.eventMap = {};
    } else if (!callback) {
      // event 存在，但callback不存在
      delete this.eventMap[event];
    } else {
      // event 存在，callback 存在，清除匹配的方法
      const events = this.eventMap[event] || [];
      let { length } = events;

      for (let i = 0; i < length; i += 1) {
        if (events[i].callback === callback) {
          events.splice(i, 1);
          length -= 1;
          i -= 1;
        }
      }

      if (events.length === 0) {
        delete this.eventMap[event];
      }
    }

    return this;
  }

  // 获取当前所有的事件
  getEvents() {
    return this.eventMap;
  }
}

export default EventEmitter.getInstance();
